So we can avoid calculating metadata for matrices all the time.
int i;
graphene_rect_t transformed_bounds;
- graphene_matrix_transform_bounds (&builder->current_modelview, &rect->bounds, &transformed_bounds);
+ graphene_matrix_transform_bounds (builder->current_modelview, &rect->bounds, &transformed_bounds);
outline[0] = transformed_bounds.origin.x;
outline[1] = transformed_bounds.origin.y;
/* Prepare outline */
outline = *rounded_outline;
- graphene_matrix_transform_bounds (&builder->current_modelview,
+ graphene_matrix_transform_bounds (builder->current_modelview,
&outline.bounds, &outline.bounds);
for (i = 0; i < 4; i ++)
{
default:
{
- graphene_matrix_t prev_mv;
graphene_matrix_t transform, transformed_mv;
graphene_matrix_init_translate (&transform,
&GRAPHENE_POINT3D_INIT(dx, dy, 1.0));
- graphene_matrix_multiply (&transform, &builder->current_modelview, &transformed_mv);
- prev_mv = ops_set_modelview (builder, &transformed_mv);
+ graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv);
+ ops_push_modelview (builder, &transformed_mv);
gsk_gl_renderer_add_render_ops (self, child, builder);
-
- ops_set_modelview (builder, &prev_mv);
+ ops_pop_modelview (builder);
}
}
}
RenderOpBuilder *builder)
{
GskRenderNode *child = gsk_transform_node_get_child (node);
- graphene_matrix_t prev_mv;
graphene_matrix_t transform, transformed_mv;
graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node));
- graphene_matrix_multiply (&transform, &builder->current_modelview, &transformed_mv);
- prev_mv = ops_set_modelview (builder, &transformed_mv);
+ graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv);
+ ops_push_modelview (builder, &transformed_mv);
gsk_gl_renderer_add_render_ops (self, child, builder);
-
- ops_set_modelview (builder, &prev_mv);
+ ops_pop_modelview (builder);
}
static inline void
GskRoundedRect child_clip;
transformed_clip = *gsk_clip_node_peek_clip (node);
- graphene_matrix_transform_bounds (&builder->current_modelview, &transformed_clip, &transformed_clip);
+ graphene_matrix_transform_bounds (builder->current_modelview, &transformed_clip, &transformed_clip);
graphene_rect_intersection (&transformed_clip,
&builder->current_clip.bounds,
int i;
transformed_clip = child_clip;
- graphene_matrix_transform_bounds (&builder->current_modelview, &child_clip.bounds, &transformed_clip.bounds);
+ graphene_matrix_transform_bounds (builder->current_modelview, &child_clip.bounds, &transformed_clip.bounds);
if (graphene_rect_contains_rect (&builder->current_clip.bounds,
&transformed_clip.bounds))
RenderOp op;
graphene_matrix_t identity;
graphene_matrix_t prev_projection;
- graphene_matrix_t prev_modelview;
graphene_rect_t prev_viewport;
graphene_matrix_t item_proj;
int blurred_texture_id;
op.op = OP_CLEAR;
ops_add (builder, &op);
prev_projection = ops_set_projection (builder, &item_proj);
- prev_modelview = ops_set_modelview (builder, &identity);
+ ops_push_modelview (builder, &identity);
prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
/* Draw outline */
ops_set_clip (builder, &prev_clip);
ops_set_viewport (builder, &prev_viewport);
- ops_set_modelview (builder, &prev_modelview);
+ ops_pop_modelview (builder);
ops_set_projection (builder, &prev_projection);
ops_set_render_target (builder, prev_render_target);
RenderOp op;
graphene_matrix_t identity;
graphene_matrix_t prev_projection;
- graphene_matrix_t prev_modelview;
graphene_rect_t prev_viewport;
graphene_matrix_t item_proj;
GskRoundedRect prev_clip;
op.op = OP_CLEAR;
ops_add (builder, &op);
prev_projection = ops_set_projection (builder, &item_proj);
- prev_modelview = ops_set_modelview (builder, &identity);
+ ops_push_modelview (builder, &identity);
prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (min_x * scale,
min_y * scale,
width, height));
ops_set_clip (builder, &prev_clip);
ops_set_viewport (builder, &prev_viewport);
- ops_set_modelview (builder, &prev_modelview);
+ ops_pop_modelview (builder);
ops_set_projection (builder, &prev_projection);
ops_set_render_target (builder, prev_render_target);
memset (&render_op_builder, 0, sizeof (render_op_builder));
render_op_builder.renderer = self;
render_op_builder.current_projection = projection;
- render_op_builder.current_modelview = modelview;
render_op_builder.current_viewport = *viewport;
render_op_builder.current_opacity = 1.0f;
render_op_builder.render_ops = self->render_ops;
gsk_rounded_rect_init_from_rect (&render_op_builder.current_clip, viewport, 0.0f);
+ ops_push_modelview (&render_op_builder, &modelview);
if (fbo_id != 0)
ops_set_render_target (&render_op_builder, fbo_id);
/* We correctly reset the state everywhere */
g_assert_cmpint (render_op_builder.current_render_target, ==, fbo_id);
+ ops_pop_modelview (&render_op_builder);
+ ops_finish (&render_op_builder);
/*g_message ("Ops: %u", self->render_ops->len);*/
#include "gskglrenderopsprivate.h"
+void
+ops_finish (RenderOpBuilder *builder)
+{
+ if (builder->mv_stack)
+ g_array_free (builder->mv_stack, TRUE);
+}
+
+
static inline void
rgba_to_float (const GdkRGBA *c,
float *f)
float
ops_get_scale (const RenderOpBuilder *builder)
{
- const graphene_matrix_t *mv = &builder->current_modelview;
- graphene_vec3_t col1;
- graphene_vec3_t col2;
+ const MatrixStackEntry *head;
- /* TODO: We should probably split this up into two values... */
-
- graphene_vec3_init (&col1,
- graphene_matrix_get_value (mv, 0, 0),
- graphene_matrix_get_value (mv, 1, 0),
- graphene_matrix_get_value (mv, 2, 0));
+ g_assert (builder->mv_stack != NULL);
+ g_assert (builder->mv_stack->len >= 1);
- graphene_vec3_init (&col2,
- graphene_matrix_get_value (mv, 0, 1),
- graphene_matrix_get_value (mv, 1, 1),
- graphene_matrix_get_value (mv, 2, 1));
+ head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
- return MAX (graphene_vec3_length (&col1),
- graphene_vec3_length (&col2));
+ return head->metadata.scale;
}
static inline gboolean
return TRUE;
}
+static void
+extract_matrix_metadata (const graphene_matrix_t *m,
+ OpsMatrixMetadata *md)
+{
+ graphene_vec3_t col1;
+ graphene_vec3_t col2;
+
+ /* Is this matrix JUST a translation? */
+ md->is_only_translation = matrix_is_only_translation (m);
+
+ /* TODO: We should probably split this up into two values... */
+
+ /* Scale */
+ graphene_vec3_init (&col1,
+ graphene_matrix_get_value (m, 0, 0),
+ graphene_matrix_get_value (m, 1, 0),
+ graphene_matrix_get_value (m, 2, 0));
+
+ graphene_vec3_init (&col2,
+ graphene_matrix_get_value (m, 0, 1),
+ graphene_matrix_get_value (m, 1, 1),
+ graphene_matrix_get_value (m, 2, 1));
+
+ md->scale = MAX (graphene_vec3_length (&col1),
+ graphene_vec3_length (&col2));
+
+}
+
+
void
ops_transform_bounds_modelview (const RenderOpBuilder *builder,
const graphene_rect_t *src,
graphene_rect_t *dst)
{
- if (builder->modelview_is_translation)
+ const MatrixStackEntry *head;
+
+ g_assert (builder->mv_stack != NULL);
+ g_assert (builder->mv_stack->len >= 1);
+
+ head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
+
+ if (head->metadata.is_only_translation)
{
graphene_vec4_t row4;
/* TODO: We could do the get_row here only once, when setting the new modelview matrix. */
- graphene_matrix_get_row (&builder->current_modelview, 3, &row4);
+ graphene_matrix_get_row (builder->current_modelview, 3, &row4);
*dst = *src;
graphene_rect_offset (dst, graphene_vec4_get_x (&row4), graphene_vec4_get_y (&row4));
}
else
{
- graphene_matrix_transform_bounds (&builder->current_modelview,
+ graphene_matrix_transform_bounds (builder->current_modelview,
src,
dst);
}
}
if (memcmp (&empty_matrix, &builder->program_state[program->index].modelview, sizeof (graphene_matrix_t)) == 0 ||
- memcmp (&builder->current_modelview, &builder->program_state[program->index].modelview, sizeof (graphene_matrix_t)) != 0)
+ memcmp (builder->current_modelview, &builder->program_state[program->index].modelview, sizeof (graphene_matrix_t)) != 0)
{
op.op = OP_CHANGE_MODELVIEW;
- op.modelview = builder->current_modelview;
+ op.modelview = *builder->current_modelview;
g_array_append_val (builder->render_ops, op);
- builder->program_state[program->index].modelview = builder->current_modelview;
+ builder->program_state[program->index].modelview = *builder->current_modelview;
}
if (memcmp (&empty_rect, &builder->program_state[program->index].viewport, sizeof (graphene_rect_t)) == 0 ||
return prev_clip;
}
-graphene_matrix_t
+static void
ops_set_modelview (RenderOpBuilder *builder,
const graphene_matrix_t *modelview)
{
RenderOp op;
- graphene_matrix_t prev_mv;
if (builder->current_program &&
memcmp (&builder->program_state[builder->current_program->index].modelview, modelview,
sizeof (graphene_matrix_t)) == 0)
- return *modelview;
+ return;
if (builder->render_ops->len > 0)
{
if (builder->current_program != NULL)
builder->program_state[builder->current_program->index].modelview = *modelview;
+}
- prev_mv = builder->current_modelview;
- builder->current_modelview = *modelview;
- builder->modelview_is_translation = matrix_is_only_translation (modelview);
+void
+ops_push_modelview (RenderOpBuilder *builder,
+ const graphene_matrix_t *mv)
+{
+ MatrixStackEntry *entry;
- return prev_mv;
+ if (G_UNLIKELY (builder->mv_stack == NULL))
+ builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
+
+ g_assert (builder->mv_stack != NULL);
+
+ g_array_set_size (builder->mv_stack, builder->mv_stack->len + 1);
+ entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
+
+ entry->matrix = *mv;
+ extract_matrix_metadata (mv, &entry->metadata);
+
+ builder->current_modelview = &entry->matrix;
+ ops_set_modelview (builder, mv);
+}
+
+void
+ops_pop_modelview (RenderOpBuilder *builder)
+{
+ const graphene_matrix_t *m;
+ const MatrixStackEntry *head;
+
+ g_assert (builder->mv_stack);
+ g_assert (builder->mv_stack->len >= 1);
+
+ builder->mv_stack->len --;
+ head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
+ m = &head->matrix;
+
+ if (builder->mv_stack->len >= 1)
+ {
+ builder->current_modelview = m;
+ ops_set_modelview (builder, m);
+ }
+ else
+ {
+ builder->current_modelview = NULL;
+ }
}
graphene_matrix_t
#define GL_N_VERTICES 6
#define GL_N_PROGRAMS 12
+
+
+typedef struct
+{
+ guint is_only_translation : 1;
+ float scale;
+} OpsMatrixMetadata;
+
+typedef struct
+{
+ graphene_matrix_t matrix;
+ OpsMatrixMetadata metadata;
+} MatrixStackEntry;
+
enum {
OP_NONE,
OP_CHANGE_OPACITY = 1,
int current_texture;
GskRoundedRect current_clip;
- graphene_matrix_t current_modelview;
- guint modelview_is_translation : 1;
-
graphene_matrix_t current_projection;
graphene_rect_t current_viewport;
float current_opacity;
GArray *render_ops;
GskGLRenderer *renderer;
+
+ /* Stack of modelview matrices */
+ GArray *mv_stack;
+ /* Pointer into mv_stack */
+ const graphene_matrix_t *current_modelview;
} RenderOpBuilder;
+void ops_finish (RenderOpBuilder *builder);
+void ops_push_modelview (RenderOpBuilder *builder,
+ const graphene_matrix_t *mv);
+void ops_pop_modelview (RenderOpBuilder *builder);
float ops_get_scale (const RenderOpBuilder *builder);
void ops_set_program (RenderOpBuilder *builder,
GskRoundedRect ops_set_clip (RenderOpBuilder *builder,
const GskRoundedRect *clip);
-graphene_matrix_t ops_set_modelview (RenderOpBuilder *builder,
- const graphene_matrix_t *modelview);
-
void ops_transform_bounds_modelview (const RenderOpBuilder *builder,
const graphene_rect_t *src,
graphene_rect_t *dst);